#ifndef _SE_SOURCELIBRARY_
#define _SE_SOURCELIBRARY_

#include <unordered_map>

namespace SE
{
	template<class _KeyTy, class _ValTy>
	class SourceLibrary
	{
	protected:
		std::unordered_map<_KeyTy, _ValTy> mSources;

	public:
		SourceLibrary() = default;
		virtual ~SourceLibrary() = default;

		bool store(const _KeyTy& key, const _ValTy& source)
		{
			if (mSources.end() != mSources.find(key))
			{
				mSources[key] = source;
				return true;
			}
			return false;
		}
		_ValTy& fetch(const _KeyTy& key)
		{
			return mSources[key];
		}
		bool erase(const _KeyTy& key)
		{
			auto it = mSources.find(key);
			if (mSources.end() != it)
			{
				mSources.erase(it);
				return true;
			}
			else
			{
				return false;
			}
		}
		void clear()
		{
			mSources.clear();
		}
		/// <summary>
		/// If the mapping from this key to resource exists, then just fetch it.
		/// If the this mapping do not exist, then create this resource by 'loadFunc', put it into this ResourceLibrary and then return it.
		/// </summary>
		/// <typeparam name="_LoadF"> The function to create resource. </typeparam>
		/// <typeparam name="..._Args"> The paramters to create resource. </typeparam>
		/// <param name="key"> The key value of mapping. </param>
		/// <param name="loadFunc"> The function to create resource. </param>
		/// <param name="...args"> The paramters to create resource. </param>
		/// <returns> The resource with the specific key. </returns>
		template <typename _LoadF, typename ..._Args>
		_ValTy& load(const _KeyTy& key, const _LoadF& loadFunc, _Args&& ...args)
		{
			if (mSources.end() != mSources.find(key))
			{
				return mSources[key];
			}
			else
			{
				mSources[key] = loadFunc(std::forward<_Args>(args)...);
				return mSources[key];
			}
		}

		bool exists(const _KeyTy& key) const
		{
			return (mSources.end() != mSources.find(key)) ? true : false;
		}
	};
} // !namespace SE

#endif // !_SE_SOURCELIBRARY_